#include <libgc/libgc.h>
#include <iostream>

struct str2 {
  gc_ptr<int> p;
};

struct str1 {
  gc_ptr<str2> p;
};

int main (void) {
  /// Выделение памяти под "ручной" объект типа str1
  str1 * s = (str1 *) malloc (sizeof(str1));
  /// Выделение управляемой памяти под управляемый объект
  /// внутри "ручного"
  s->p = gc_new<str2>();
  /// Вызов функции register_object, сообщающей сборщику мусора,
  /// что на управляемый объект, расположенный в памяти по адресу
  /// &(s->p), появилась дополнительная "внешняя" ссылка
  register_object(&(s->p));
  /// Выделение управляемой памяти под управляемый массив
  s->p->p = gc_new<int>(1000);
  
  /// Принудительный вызов сборки мусора.
  /// После выполнения данной функции ни один выделенный объект
  /// не должн быть удален, т.к.
  /// объект s --- ручной,
  /// объект s->p --- управляемый, на который существует ссылка из ручного,
  /// объект s->p->p --- управляемый, на который существует ссылка
  /// 	из автоматического, достижимого из "ручного"
  mark_and_sweep();
  
  /// Сообщение сборщику мусора о том, что на объект,
  /// лежащий по адресу &(s->p) одна из ссылок из
  /// "ручных" объектов более не требуется
  unregister_object(&(s->p));
  s->p = NULL;
  
  /// Принудительный вызов сборки мусора.
  /// После выполнения данной функции объекты
  /// s->p и s->p->p должны быть удалены.
  mark_and_sweep();
  
  /// Вызов функции transfer_to_automatic_objects(void * s)
  /// переводит "ручной" объект, расположенный по адресу &s,
  /// в управляемые.
  /// Фактически это означает, что объект s более не нужен
  /// пользователю и его можно удалить во время ближайшей сборки мусора
  transfer_to_automatic_objects(s);
  
  /// Принудительный вызов сборки мусора.
  /// После выполнения данной функции объект
  /// s должен быть удален.
  mark_and_sweep();

  return 0;
}